package com.zlc.workflow.core.instance.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zlc.common.core.process.model.vo.StoneNodeApproveUserConfigVo;
import com.zlc.common.core.process.model.vo.StoneProcessInstanceVo;
import com.zlc.common.core.process.model.vo.StoneTaskHistoryVo;
import com.zlc.common.core.process.service.StoneNodeApproveUserConfigService;
import com.zlc.common.core.process.service.StoneProcessInstanceService;
import com.zlc.common.core.process.service.StoneTaskHistoryService;
import com.zlc.common.core.user.model.vo.MayanPlatUserVo;
import com.zlc.common.core.user.service.MayanPlatUserService;
import com.zlc.common.util.JsonHelper;
import com.zlc.workflow.constant.UserTypeEnum;
import com.zlc.workflow.core.instance.service.WorkflowService;
import com.zlc.workflow.flow.NodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WorkflowServiceImpl implements WorkflowService {

    @Autowired
    private StoneNodeApproveUserConfigService stoneNodeApproveUserConfigService;
    @Autowired
    private StoneProcessInstanceService stoneProcessInstanceService;
    @Autowired
    private MayanPlatUserService mayanPlatUserService;
    @Autowired
    private StoneTaskHistoryService stoneTaskHistoryService;

    private List<MayanPlatUserVo> getApprovalUser(List<StoneNodeApproveUserConfigVo> userConfigVos,String processInstanceId, Map<String,Object> formData){
        List<MayanPlatUserVo> result = new ArrayList<>();
        for(StoneNodeApproveUserConfigVo userConfigVo : userConfigVos){
            List<MayanPlatUserVo> platUserVos = getApprovalUserByConfig(userConfigVo, processInstanceId, formData);
            if(!ObjectUtils.isEmpty(platUserVos)){
                result.addAll(platUserVos);
            }
        }
        return result;
    }

    @Override
    public List<MayanPlatUserVo> getApprovalUserByConfig(StoneNodeApproveUserConfigVo userConfigVo, String processInstanceId, Map<String, Object> formData) {
        List<MayanPlatUserVo> result = new ArrayList<>();
        String userType = userConfigVo.getUserType();
        if(UserTypeEnum.START.getType().equals(userType)){
            MayanPlatUserVo userVo = getProcessInstanceStarter(processInstanceId);
            if(!ObjectUtils.isEmpty(userVo)){
                result.add(userVo);
            }
        }else if(UserTypeEnum.VARIABLE.getType().equals(userType)){
            String approveUser = userConfigVo.getApproveUser();
            if (!ObjectUtils.isEmpty(approveUser) && !ObjectUtils.isEmpty(formData)) {
                approveUser = NodeUtils.transferVariable(formData, approveUser);
                List<String> accountList = StrUtil.split(approveUser, ";");
                List<MayanPlatUserVo> mayanPlatUserVos = mayanPlatUserService.queryByUserAccounts(accountList);
                if(!ObjectUtils.isEmpty(mayanPlatUserVos)){
                    result.addAll(mayanPlatUserVos);
                }
            }
        }else if(UserTypeEnum.ACCOUNT.getType().equals(userType)){
            String approveUser = userConfigVo.getApproveUser();
            if(!ObjectUtils.isEmpty(approveUser)){
                MayanPlatUserVo mayanPlatUserVo = JsonHelper.jsonToObject(approveUser, MayanPlatUserVo.class);
                if(!ObjectUtils.isEmpty(mayanPlatUserVo)){
                    result.add(mayanPlatUserVo);
                }
            }
        }else if(UserTypeEnum.NODE_APPROVE.getType().equals(userType)){
            String approveUser = userConfigVo.getApproveUser();
            if(!ObjectUtils.isEmpty(approveUser)){
                List<String> nodeIds = StrUtil.split(approveUser, ";");
                List<MayanPlatUserVo> userVos = getNodeApprovalUserByNodeId(processInstanceId, nodeIds);
                if(!ObjectUtils.isEmpty(userVos)){
                    result.addAll(userVos);
                }
            }
        }else if(UserTypeEnum.ALL_APPROVE.getType().equals(userType)){
            List<MayanPlatUserVo> userVos = getAllApprovalUserByProcessInstanceId(processInstanceId);
            if(!ObjectUtils.isEmpty(userVos)){
                result.addAll(userVos);
            }
        }
        return result;
    }

    @Override
    public List<MayanPlatUserVo> getApprovalUserByEventId(String processInstanceId,String eventId, Map<String,Object> formData) {
        if(ObjectUtils.isEmpty(processInstanceId) || ObjectUtils.isEmpty(eventId)){
            return new ArrayList<>();
        }
        List<StoneNodeApproveUserConfigVo> userConfigVos = stoneNodeApproveUserConfigService.getByEventId(eventId);
        return getApprovalUser(userConfigVos,processInstanceId,formData);
    }

    @Override
    public List<MayanPlatUserVo> getApprovalUserByConfigId(String processInstanceId,String configId, Map<String,Object> formData) {
        if(ObjectUtils.isEmpty(processInstanceId) || ObjectUtils.isEmpty(configId)){
            return new ArrayList<>();
        }
        List<StoneNodeApproveUserConfigVo> userConfigVos = stoneNodeApproveUserConfigService.getByConfigId(configId);
        return getApprovalUser(userConfigVos,processInstanceId,formData);
    }

    @Override
    public MayanPlatUserVo getProcessInstanceStarter(String processInstanceId) {
        StoneProcessInstanceVo instance = stoneProcessInstanceService.getByProcessInstanceId(processInstanceId);
        if(!ObjectUtils.isEmpty(instance)){
            return mayanPlatUserService.queryByUserAccount(instance.getStarter());
        }
        return null;
    }

    @Override
    public List<MayanPlatUserVo> getAllApprovalUserByProcessInstanceId(String processInstanceId) {
        List<StoneTaskHistoryVo> taskHistoryVos = stoneTaskHistoryService.getByProcessInstanceId(processInstanceId);
        if(ObjectUtils.isEmpty(taskHistoryVos)){
            return new ArrayList<>();
        }
        List<String> actorIds = taskHistoryVos.stream().map(StoneTaskHistoryVo::getActorId).collect(Collectors.toList());
        if(ObjectUtils.isEmpty(actorIds)){
            return new ArrayList<>();
        }
        return mayanPlatUserService.queryByUserAccounts(actorIds);
    }

    @Override
    public List<MayanPlatUserVo> getNodeApprovalUserByNodeId(String processInstanceId, List<String> nodeIds) {
        List<StoneTaskHistoryVo> taskHistoryVos = stoneTaskHistoryService.getByProcessInstanceId(processInstanceId);
        if(ObjectUtils.isEmpty(taskHistoryVos)){
            return new ArrayList<>();
        }
        List<String> actorIds = taskHistoryVos.stream().filter(t -> nodeIds.contains(t.getNodeId()))
                .map(StoneTaskHistoryVo::getActorId).collect(Collectors.toList());
        if(ObjectUtils.isEmpty(actorIds)){
            return new ArrayList<>();
        }
        return mayanPlatUserService.queryByUserAccounts(actorIds);
    }
}
